{
  "cells": [
    {
      "attachments": {},
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/pinecone-io/examples/blob/master/learn/recommendation/movie-recommender/xx_train_movie_recommender.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/pinecone-io/examples/blob/master/learn/recommendation/movie-recommender/xx_train_movie_recommender.ipynb)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AhVk6WLnOqXs"
      },
      "outputs": [],
      "source": [
        "!nvidia-smi"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "xg3g40e2DnrS",
        "outputId": "c2a5ed97-8ec3-45a8-a84d-ed1702f6c9c6"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
            "Collecting datasets\n",
            "  Downloading datasets-2.4.0-py3-none-any.whl (365 kB)\n",
            "\u001b[K     |\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 365 kB 4.7 MB/s \n",
            "\u001b[?25hRequirement already satisfied: tensorflow in /usr/local/lib/python3.7/dist-packages (2.8.2+zzzcolab20220719082949)\n",
            "Collecting huggingface-hub\n",
            "  Downloading huggingface_hub-0.8.1-py3-none-any.whl (101 kB)\n",
            "\u001b[K     |\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 101 kB 13.1 MB/s \n",
            "\u001b[?25hRequirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.7/dist-packages (from datasets) (1.21.6)\n",
            "Collecting xxhash\n",
            "  Downloading xxhash-3.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (212 kB)\n",
            "\u001b[K     |\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 212 kB 55.8 MB/s \n",
            "\u001b[?25hRequirement already satisfied: pandas in /usr/local/lib/python3.7/dist-packages (from datasets) (1.3.5)\n",
            "Requirement already satisfied: packaging in /usr/local/lib/python3.7/dist-packages (from datasets) (21.3)\n",
            "Requirement already satisfied: fsspec[http]>=2021.11.1 in /usr/local/lib/python3.7/dist-packages (from datasets) (2022.7.1)\n",
            "Collecting multiprocess\n",
            "  Downloading multiprocess-0.70.13-py37-none-any.whl (115 kB)\n",
            "\u001b[K     |\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 115 kB 61.2 MB/s \n",
            "\u001b[?25hRequirement already satisfied: importlib-metadata in /usr/local/lib/python3.7/dist-packages (from datasets) (4.12.0)\n",
            "Collecting responses<0.19\n",
            "  Downloading responses-0.18.0-py3-none-any.whl (38 kB)\n",
            "Requirement already satisfied: pyarrow>=6.0.0 in /usr/local/lib/python3.7/dist-packages (from datasets) (6.0.1)\n",
            "Requirement already satisfied: aiohttp in /usr/local/lib/python3.7/dist-packages (from datasets) (3.8.1)\n",
            "Requirement already satisfied: requests>=2.19.0 in /usr/local/lib/python3.7/dist-packages (from datasets) (2.23.0)\n",
            "Requirement already satisfied: dill<0.3.6 in /usr/local/lib/python3.7/dist-packages (from datasets) (0.3.5.1)\n",
            "Requirement already satisfied: tqdm>=4.62.1 in /usr/local/lib/python3.7/dist-packages (from datasets) (4.64.0)\n",
            "Requirement already satisfied: filelock in /usr/local/lib/python3.7/dist-packages (from huggingface-hub) (3.8.0)\n",
            "Requirement already satisfied: typing-extensions>=3.7.4.3 in /usr/local/lib/python3.7/dist-packages (from huggingface-hub) (4.1.1)\n",
            "Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.7/dist-packages (from huggingface-hub) (6.0)\n",
            "Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /usr/local/lib/python3.7/dist-packages (from packaging->datasets) (3.0.9)\n",
            "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19.0->datasets) (1.24.3)\n",
            "Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19.0->datasets) (2.10)\n",
            "Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19.0->datasets) (3.0.4)\n",
            "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19.0->datasets) (2022.6.15)\n",
            "Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1\n",
            "  Downloading urllib3-1.25.11-py2.py3-none-any.whl (127 kB)\n",
            "\u001b[K     |\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 127 kB 62.7 MB/s \n",
            "\u001b[?25hRequirement already satisfied: google-pasta>=0.1.1 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (0.2.0)\n",
            "Requirement already satisfied: absl-py>=0.4.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (1.2.0)\n",
            "Requirement already satisfied: wrapt>=1.11.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (1.14.1)\n",
            "Requirement already satisfied: grpcio<2.0,>=1.24.3 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (1.47.0)\n",
            "Requirement already satisfied: astunparse>=1.6.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (1.6.3)\n",
            "Requirement already satisfied: libclang>=9.0.1 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (14.0.6)\n",
            "Requirement already satisfied: six>=1.12.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (1.15.0)\n",
            "Requirement already satisfied: termcolor>=1.1.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (1.1.0)\n",
            "Requirement already satisfied: tensorflow-io-gcs-filesystem>=0.23.1 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (0.26.0)\n",
            "Requirement already satisfied: gast>=0.2.1 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (0.5.3)\n",
            "Requirement already satisfied: setuptools in /usr/local/lib/python3.7/dist-packages (from tensorflow) (57.4.0)\n",
            "Requirement already satisfied: keras-preprocessing>=1.1.1 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (1.1.2)\n",
            "Requirement already satisfied: tensorflow-estimator<2.9,>=2.8 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (2.8.0)\n",
            "Requirement already satisfied: opt-einsum>=2.3.2 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (3.3.0)\n",
            "Requirement already satisfied: keras<2.9,>=2.8.0rc0 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (2.8.0)\n",
            "Requirement already satisfied: flatbuffers>=1.12 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (2.0)\n",
            "Requirement already satisfied: h5py>=2.9.0 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (3.1.0)\n",
            "Requirement already satisfied: tensorboard<2.9,>=2.8 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (2.8.0)\n",
            "Requirement already satisfied: protobuf<3.20,>=3.9.2 in /usr/local/lib/python3.7/dist-packages (from tensorflow) (3.17.3)\n",
            "Requirement already satisfied: wheel<1.0,>=0.23.0 in /usr/local/lib/python3.7/dist-packages (from astunparse>=1.6.0->tensorflow) (0.37.1)\n",
            "Requirement already satisfied: cached-property in /usr/local/lib/python3.7/dist-packages (from h5py>=2.9.0->tensorflow) (1.5.2)\n",
            "Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.7/dist-packages (from tensorboard<2.9,>=2.8->tensorflow) (3.4.1)\n",
            "Requirement already satisfied: google-auth<3,>=1.6.3 in /usr/local/lib/python3.7/dist-packages (from tensorboard<2.9,>=2.8->tensorflow) (1.35.0)\n",
            "Requirement already satisfied: tensorboard-data-server<0.7.0,>=0.6.0 in /usr/local/lib/python3.7/dist-packages (from tensorboard<2.9,>=2.8->tensorflow) (0.6.1)\n",
            "Requirement already satisfied: tensorboard-plugin-wit>=1.6.0 in /usr/local/lib/python3.7/dist-packages (from tensorboard<2.9,>=2.8->tensorflow) (1.8.1)\n",
            "Requirement already satisfied: google-auth-oauthlib<0.5,>=0.4.1 in /usr/local/lib/python3.7/dist-packages (from tensorboard<2.9,>=2.8->tensorflow) (0.4.6)\n",
            "Requirement already satisfied: werkzeug>=0.11.15 in /usr/local/lib/python3.7/dist-packages (from tensorboard<2.9,>=2.8->tensorflow) (1.0.1)\n",
            "Requirement already satisfied: cachetools<5.0,>=2.0.0 in /usr/local/lib/python3.7/dist-packages (from google-auth<3,>=1.6.3->tensorboard<2.9,>=2.8->tensorflow) (4.2.4)\n",
            "Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.7/dist-packages (from google-auth<3,>=1.6.3->tensorboard<2.9,>=2.8->tensorflow) (0.2.8)\n",
            "Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.7/dist-packages (from google-auth<3,>=1.6.3->tensorboard<2.9,>=2.8->tensorflow) (4.9)\n",
            "Requirement already satisfied: requests-oauthlib>=0.7.0 in /usr/local/lib/python3.7/dist-packages (from google-auth-oauthlib<0.5,>=0.4.1->tensorboard<2.9,>=2.8->tensorflow) (1.3.1)\n",
            "Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.7/dist-packages (from importlib-metadata->datasets) (3.8.1)\n",
            "Requirement already satisfied: pyasn1<0.5.0,>=0.4.6 in /usr/local/lib/python3.7/dist-packages (from pyasn1-modules>=0.2.1->google-auth<3,>=1.6.3->tensorboard<2.9,>=2.8->tensorflow) (0.4.8)\n",
            "Requirement already satisfied: oauthlib>=3.0.0 in /usr/local/lib/python3.7/dist-packages (from requests-oauthlib>=0.7.0->google-auth-oauthlib<0.5,>=0.4.1->tensorboard<2.9,>=2.8->tensorflow) (3.2.0)\n",
            "Requirement already satisfied: charset-normalizer<3.0,>=2.0 in /usr/local/lib/python3.7/dist-packages (from aiohttp->datasets) (2.1.0)\n",
            "Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.7/dist-packages (from aiohttp->datasets) (1.8.1)\n",
            "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.7/dist-packages (from aiohttp->datasets) (1.2.0)\n",
            "Requirement already satisfied: asynctest==0.13.0 in /usr/local/lib/python3.7/dist-packages (from aiohttp->datasets) (0.13.0)\n",
            "Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in /usr/local/lib/python3.7/dist-packages (from aiohttp->datasets) (4.0.2)\n",
            "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.7/dist-packages (from aiohttp->datasets) (22.1.0)\n",
            "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.7/dist-packages (from aiohttp->datasets) (6.0.2)\n",
            "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.7/dist-packages (from aiohttp->datasets) (1.3.1)\n",
            "Requirement already satisfied: python-dateutil>=2.7.3 in /usr/local/lib/python3.7/dist-packages (from pandas->datasets) (2.8.2)\n",
            "Requirement already satisfied: pytz>=2017.3 in /usr/local/lib/python3.7/dist-packages (from pandas->datasets) (2022.2.1)\n",
            "Installing collected packages: urllib3, xxhash, responses, multiprocess, huggingface-hub, datasets\n",
            "  Attempting uninstall: urllib3\n",
            "    Found existing installation: urllib3 1.24.3\n",
            "    Uninstalling urllib3-1.24.3:\n",
            "      Successfully uninstalled urllib3-1.24.3\n",
            "Successfully installed datasets-2.4.0 huggingface-hub-0.8.1 multiprocess-0.70.13 responses-0.18.0 urllib3-1.25.11 xxhash-3.0.0\n"
          ]
        }
      ],
      "source": [
        "!pip install datasets tensorflow huggingface-hub"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "y1bOPXx8va64"
      },
      "source": [
        "# Load and Prepare Dataset"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 104,
          "referenced_widgets": [
            "5d4fad1f0c774e8b8b59c7fd5d12d2e0",
            "4c54d907905749d193ffea37835ece53",
            "ca4f453b819e4ee797b8463f396264d7",
            "014c0e57dc3d45f29c037be4e967c786",
            "2536a807f78440609df3b98a2c4d301b",
            "4be08c9e5ed24d72bd6b2e0233bf36cb",
            "3dfeee373bdc457d820799a6f53f7b92",
            "448a0f4829524d3895d245310f78901e",
            "7f544b0f809e4d18beac3b1ccafd5015",
            "fa23fdc4e17c4370ab14255bbd68fcc3",
            "d731bf4870da4219a54629bb9015d9a3"
          ]
        },
        "id": "oAiKitZRxLNN",
        "outputId": "7f8f8a51-032c-4f3d-f2bc-116852c2b9f3"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "WARNING:datasets.builder:Using custom data configuration default\n",
            "WARNING:datasets.builder:Reusing dataset movielens-recent-ratings (/root/.cache/huggingface/datasets/pinecone___movielens-recent-ratings/default/0.0.0/0b5cf78c3c23d9db1c33d17d7d490a06b45c6d9f00a6691aa005c6fcad1c8b82)\n"
          ]
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "5d4fad1f0c774e8b8b59c7fd5d12d2e0",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "  0%|          | 0/2 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "from datasets import load_dataset\n",
        "\n",
        "movies = load_dataset('pinecone/movielens-recent-ratings')\n",
        "train = movies['train'].to_pandas()\n",
        "test = movies['test'].to_pandas()\n",
        "\n",
        "del movies"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-pxufhHbzheG"
      },
      "source": [
        "# Training the Model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "UZpso4PiKSvZ"
      },
      "outputs": [],
      "source": [
        "# ROW_COUNT = train.shape[0]\n",
        "EMBEDDING_SIZE = 32\n",
        "NUM_USERS = train['user_id'].nunique()\n",
        "NUM_MOVIES = train['movie_id'].nunique()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "vCEJnfthwqPn",
        "outputId": "74a314d8-9e83-4c89-d2aa-22fb5e56b426"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "(10269, 35710)"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "NUM_MOVIES, NUM_USERS"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "Oo9JXAb5yhe-"
      },
      "outputs": [],
      "source": [
        "from tensorflow import keras\n",
        "from tensorflow.keras import layers"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6r-s5bir0shD"
      },
      "source": [
        "### User Model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "D3ERlhnIyJdQ",
        "outputId": "5b003b59-7c6b-411d-93ee-bdebe28df96f"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Model: \"model\"\n",
            "_________________________________________________________________\n",
            " Layer (type)                Output Shape              Param #   \n",
            "=================================================================\n",
            " user_id (InputLayer)        [(None, 1)]               0         \n",
            "                                                                 \n",
            " user_emb (Embedding)        (None, 1, 32)             1142720   \n",
            "                                                                 \n",
            "=================================================================\n",
            "Total params: 1,142,720\n",
            "Trainable params: 1,142,720\n",
            "Non-trainable params: 0\n",
            "_________________________________________________________________\n"
          ]
        }
      ],
      "source": [
        "u_inputs = layers.Input(shape=(1,), name='user_id')\n",
        "user_emb = layers.Embedding(output_dim=32, input_dim=NUM_USERS, name='user_emb')(u_inputs)\n",
        "user_model = keras.Model(u_inputs, user_emb)\n",
        "user_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kCnovFvk0v2k"
      },
      "source": [
        "### Movie Model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "0kmimEqHyOmS",
        "outputId": "d520ff8b-1eae-40e4-c824-75ca679f8984"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Model: \"model_1\"\n",
            "_________________________________________________________________\n",
            " Layer (type)                Output Shape              Param #   \n",
            "=================================================================\n",
            " movie_embedding (InputLayer  [(None, 1)]              0         \n",
            " )                                                               \n",
            "                                                                 \n",
            " movie_emb (Embedding)       (None, 1, 32)             328608    \n",
            "                                                                 \n",
            "=================================================================\n",
            "Total params: 328,608\n",
            "Trainable params: 328,608\n",
            "Non-trainable params: 0\n",
            "_________________________________________________________________\n"
          ]
        }
      ],
      "source": [
        "m_inputs = layers.Input(shape=(1,), name='movie_embedding')\n",
        "movie_emb = layers.Embedding(output_dim=32, input_dim=NUM_MOVIES, name='movie_emb')(m_inputs)\n",
        "movie_model = keras.Model(m_inputs, movie_emb)\n",
        "movie_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dq1mVb_0LEdL"
      },
      "source": [
        "### Merged Model\n",
        "\n",
        "We merge the two models via a dot product layer (which is normalized, and so is equivalent to cosine similarity) between the movie embedding and user embedding layers. This allows us to optimize the two models to produce similar movie/user embeddings when the ratings between both are higher."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "id": "VbkhJam9yOo6"
      },
      "outputs": [],
      "source": [
        "merged = layers.Dot(name = 'dot_product', normalize = True, axes = 2)([movie_emb, user_emb])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "OgZZ-JLUyOrS",
        "outputId": "fc995405-ac58-4aea-d81c-2c71fb7550cb"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Model: \"model_2\"\n",
            "__________________________________________________________________________________________________\n",
            " Layer (type)                   Output Shape         Param #     Connected to                     \n",
            "==================================================================================================\n",
            " movie_embedding (InputLayer)   [(None, 1)]          0           []                               \n",
            "                                                                                                  \n",
            " user_id (InputLayer)           [(None, 1)]          0           []                               \n",
            "                                                                                                  \n",
            " movie_emb (Embedding)          (None, 1, 32)        328608      ['movie_embedding[0][0]']        \n",
            "                                                                                                  \n",
            " user_emb (Embedding)           (None, 1, 32)        1142720     ['user_id[0][0]']                \n",
            "                                                                                                  \n",
            " dot_product (Dot)              (None, 1, 1)         0           ['movie_emb[0][0]',              \n",
            "                                                                  'user_emb[0][0]']               \n",
            "                                                                                                  \n",
            "==================================================================================================\n",
            "Total params: 1,471,328\n",
            "Trainable params: 1,471,328\n",
            "Non-trainable params: 0\n",
            "__________________________________________________________________________________________________\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.7/dist-packages/keras/optimizer_v2/adam.py:105: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead.\n",
            "  super(Adam, self).__init__(name, **kwargs)\n"
          ]
        }
      ],
      "source": [
        "adam = keras.optimizers.Adam(lr=0.001)\n",
        "model = keras.Model([m_inputs, u_inputs], merged)\n",
        "model.compile(optimizer=adam, loss= 'mean_absolute_error')\n",
        "model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3XwkS8hgHM0P"
      },
      "source": [
        "Now we normalize the ratings."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "id": "W_sdoTZ6yOtf"
      },
      "outputs": [],
      "source": [
        "norm_rating_train = train.rating/5\n",
        "norm_rating_test = test.rating/5"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fBWGbnPAHP3S"
      },
      "source": [
        "And train..."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "rKUW4acOyOva",
        "outputId": "076d061c-f519-45bc-837d-b7425de857e7"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Epoch 1/10\n",
            "6825/6825 [==============================] - 31s 4ms/step - loss: 0.2525 - val_loss: 0.1437\n",
            "Epoch 2/10\n",
            "6825/6825 [==============================] - 27s 4ms/step - loss: 0.1323 - val_loss: 0.1353\n",
            "Epoch 3/10\n",
            "6825/6825 [==============================] - 29s 4ms/step - loss: 0.1197 - val_loss: 0.1311\n",
            "Epoch 4/10\n",
            "6825/6825 [==============================] - 28s 4ms/step - loss: 0.1118 - val_loss: 0.1285\n",
            "Epoch 5/10\n",
            "6825/6825 [==============================] - 27s 4ms/step - loss: 0.1063 - val_loss: 0.1272\n",
            "Epoch 6/10\n",
            "6825/6825 [==============================] - 29s 4ms/step - loss: 0.1024 - val_loss: 0.1266\n",
            "Epoch 7/10\n",
            "6825/6825 [==============================] - 27s 4ms/step - loss: 0.0995 - val_loss: 0.1260\n",
            "Epoch 8/10\n",
            "6825/6825 [==============================] - 29s 4ms/step - loss: 0.0972 - val_loss: 0.1252\n",
            "Epoch 9/10\n",
            "6825/6825 [==============================] - 28s 4ms/step - loss: 0.0953 - val_loss: 0.1249\n",
            "Epoch 10/10\n",
            "6825/6825 [==============================] - 27s 4ms/step - loss: 0.0938 - val_loss: 0.1250\n"
          ]
        }
      ],
      "source": [
        "history = model.fit([train.movie_id, train.user_id], norm_rating_train, batch_size=128,\n",
        "                              epochs = 10, validation_data = ([test.movie_id, test.user_id], norm_rating_test),\n",
        "                              verbose = 1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "l-BsSAx_DhML"
      },
      "source": [
        "### Training History"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "id": "xaDurccIybmH"
      },
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 295
        },
        "id": "nKOeCPxdybrB",
        "outputId": "6a31fee7-cbb3-4c2d-9845-6c7904557adb"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Plot history: MAE\n",
        "plt.plot(history.history['loss'], label='Training data)')\n",
        "plt.plot(history.history['val_loss'], label='Validation data)')\n",
        "plt.title('MAE')\n",
        "plt.ylabel('MAE value')\n",
        "plt.xlabel('No. epoch')\n",
        "plt.legend(loc=\"upper left\")\n",
        "plt.show()"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [],
      "name": "xx_train_movie_recommender.ipynb",
      "provenance": []
    },
    "gpuClass": "standard",
    "kernelspec": {
      "display_name": "base",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.8.13 (default, Mar 28 2022, 06:59:08) [MSC v.1916 64 bit (AMD64)]"
    },
    "vscode": {
      "interpreter": {
        "hash": "5fe10bf018ef3e697f9035d60bf60847932a12bface18908407fd371fe880db9"
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}